package interpreter;

public class Task1Solver {
	
	private double [][][][]y;
	
	public void solve(double [][][][]_y) {
		y = _y.clone();
		int ISI = 2; // |S|
		int IMI = 2; // |M|
		int IFI = 2; // |F|
		int R = 10; // R
		
		double [][][]y_mean = new double[ISI+1][IMI+1][IFI+1];
		for(int i=0; i<=ISI; i++) {
			for(int j=0; j<=IMI; j++) {
				for(int k=0; k<=IFI; k++) {
					y_mean[i][j][k] = computeMean(i,j,k, ISI, IMI, IFI, R);
				}
			}
		}
		
		double miu = y_mean[ISI][IMI][IFI];
		double []s = new double[ISI];
		for(int i=0; i<ISI; i++) {
			s[i] = y_mean[i][IMI][IFI] - miu;
		}
		double []m = new double[IMI];
		for(int j=0; j<IMI; j++) {
			m[j] = y_mean[ISI][j][IFI] - miu;
		}
		double []f = new double[IFI];
		for(int k=0; k<IFI; k++) {
			f[k] = y_mean[ISI][IMI][k] - miu;
		}
		
		double [][]niuSM = new double[ISI][IMI];
		for(int i=0; i<ISI; i++) {
			for(int j=0; j<IMI; j++) {
				niuSM[i][j] = y_mean[i][j][IFI] - s[i] - m[j] - miu;
			}
		}
		double [][]niuSF = new double[ISI][IFI];
		for(int i=0; i<ISI; i++) {
			for(int k=0; k<IFI; k++) {
				niuSF[i][k] = y_mean[i][IMI][k] - s[i] - f[k] - miu;
			}
		}
		double [][]niuMF = new double[IMI][IFI];
		for(int j=0; j<IMI; j++) {
			for(int k=0; k<IFI; k++) {
				niuMF[j][k] = y_mean[ISI][j][k] - m[j] - f[k] - miu;
			}
		}
		double [][][]niuSMF = new double[ISI][IMI][IFI];
		for(int i=0; i<ISI; i++) {
			for(int j=0; j<IMI; j++) {
				for(int k=0; k<IFI; k++) {
					niuSMF[i][j][k] = y_mean[i][j][k] - s[i] - m[j] - f[k] - niuSM[i][j] - niuSF[i][k] - niuMF[j][k] - miu;
				}
			}
		}
		double [][][][]error = new double[ISI][IMI][IFI][R];
		for(int i=0; i<ISI; i++) {
			for(int j=0; j<IMI; j++) {
				for(int k=0; k<IFI; k++) {
					for(int l=0; l<R; l++) {
						error[i][j][k][l] = y[i][j][k][l] - y_mean[i][j][k];
					}
				}
			}
		}
		
		double SS_y = 0;
		for(int i=0; i<ISI; i++) {
			for(int j=0; j<IMI; j++) {
				for(int k=0; k<IFI; k++) {
					for(int l=0; l<R; l++) {
						SS_y += y[i][j][k][l] * y[i][j][k][l];
					}
				}
			}
		}
		
		double SS_0 = ISI * IMI * IFI * R * miu * miu;
		
		double SS_S = 0;
		for(int i=0; i<ISI; i++) {
			SS_S += s[i] * s[i];
		}
		SS_S *= IMI * IFI * R;
		
		double SS_M = 0;
		for(int j=0; j<IMI; j++) {
			SS_M += m[j] * m[j];
		}
		SS_M *= ISI * IFI * R;
		
		double SS_F = 0;
		for(int k=0; k<IFI; k++) {
			SS_F += f[k] * f[k];
		}
		SS_F *= ISI * IMI * R;
		
		double SS_SM = 0;
		for(int i=0; i<ISI; i++) {
			for(int j=0; j<IMI; j++) {
				SS_SM += niuSM[i][j] * niuSM[i][j];
			}
		}
		SS_SM *= IFI * R;
		
		double SS_MF = 0;
		for(int j=0; j<IMI; j++) {
			for(int k=0; k<IFI; k++) {
				SS_MF += niuMF[j][k] * niuMF[j][k];
			}
		}
		SS_MF *= ISI * R;
		
		double SS_SF = 0;
		for(int i=0; i<ISI; i++) {
			for(int k=0; k<IFI; k++) {
				SS_SF += niuSF[i][k] * niuSF[i][k];
			}
		}
		SS_SF *= IMI * R;
		
		double SS_SMF = 0;
		for(int i=0; i<ISI; i++) {
			for(int j=0; j<IMI; j++) {
				for(int k=0; k<IFI; k++) {
					SS_SMF += niuSMF[i][j][k] * niuSMF[i][j][k];
				}
			}
		}
		SS_SMF *= R;
		
		double SS_E = 0;
		for(int i=0; i<ISI; i++) {
			for(int j=0; j<IMI; j++) {
				for(int k=0; k<IFI; k++) {
					for(int l=0; l<R; l++) {
						SS_E += error[i][j][k][l] * error[i][j][k][l];
					}
				}
			}
		}
		
		double SS_added_y = 0;
		SS_added_y += SS_0;
		SS_added_y += SS_S;
		SS_added_y += SS_M;
		SS_added_y += SS_F;
		SS_added_y += SS_SM;
		SS_added_y += SS_MF;
		SS_added_y += SS_SF;
		SS_added_y += SS_SMF;
		SS_added_y += SS_E;
		
		System.out.print("SS_added_y: "); System.out.format("%.3f%n", SS_added_y);
		System.out.print("SS_y: "); System.out.format("%.3f%n", SS_y);
		System.out.print("SS_0: "); System.out.format("%.3f%n", SS_0);
		System.out.print("SS_S: "); System.out.format("%.3f%n", SS_S);
		System.out.print("SS_M: "); System.out.format("%.3f%n", SS_M);
		System.out.print("SS_F: "); System.out.format("%.3f%n", SS_F);
		System.out.print("SS_SM: "); System.out.format("%.3f%n", SS_SM);
		System.out.print("SS_MF: "); System.out.format("%.3f%n", SS_MF);
		System.out.print("SS_SF: "); System.out.format("%.3f%n", SS_SF);
		System.out.print("SS_SMF: "); System.out.format("%.3f%n", SS_SMF);
		System.out.print("SS_E: "); System.out.format("%.3f%n", SS_E);
		
		double influence_S = 100*(SS_S/(SS_y - SS_0));
		double influence_M = 100*(SS_M/(SS_y - SS_0));
		double influence_F = 100*(SS_F/(SS_y - SS_0));
		double influence_SM = 100*(SS_SM/(SS_y - SS_0));
		double influence_MF = 100*(SS_MF/(SS_y - SS_0));
		double influence_SF = 100*(SS_SF/(SS_y - SS_0));
		double influence_SMF = 100*(SS_SMF/(SS_y - SS_0));
		double influence_E = 100*(SS_E/(SS_y - SS_0));
		
		System.out.println("-------------");
		System.out.print("influence SS_S: "); System.out.format("%.3f%n", influence_S);
		System.out.print("influence SS_M: "); System.out.format("%.3f%n", influence_M);
		System.out.print("influence SS_F: "); System.out.format("%.3f%n", influence_F);
		System.out.print("influence SS_SM: "); System.out.format("%.3f%n", influence_SM);
		System.out.print("influence SS_MF: "); System.out.format("%.3f%n", influence_MF);
		System.out.print("influence SS_SF: "); System.out.format("%.3f%n", influence_SF);
		System.out.print("influence SS_SMF: "); System.out.format("%.3f%n", influence_SMF);
		System.out.print("influence SS_E: "); System.out.format("%.3f%n", influence_E);
		
		
		double degrees_of_freedom_y = ISI * IMI * IFI * R;
		
		double std_dev_error = Math.sqrt(SS_E / (ISI * IMI * IFI * (R-1)));
		double std_dev_miu = std_dev_error * Math.sqrt(1 / degrees_of_freedom_y);
		double std_dev_S = std_dev_error * Math.sqrt( (ISI - 1) / degrees_of_freedom_y);
		double std_dev_M = std_dev_error * Math.sqrt( (IMI - 1) / degrees_of_freedom_y);
		double std_dev_F = std_dev_error * Math.sqrt( (IFI - 1) / degrees_of_freedom_y);
		double std_dev_SM = std_dev_error * Math.sqrt( ((ISI-1)*(IMI-1)) / degrees_of_freedom_y);
		double std_dev_SF = std_dev_error * Math.sqrt( ((ISI-1)*(IFI-1)) / degrees_of_freedom_y);
		double std_dev_MF = std_dev_error * Math.sqrt( ((IMI-1)*(IFI-1)) / degrees_of_freedom_y);
		double std_dev_SMF = std_dev_error * Math.sqrt( ((ISI-1)*(IMI-1)*(IFI-1)) / degrees_of_freedom_y);
		
		
		
		System.out.print("MIU 90%: ");
		printConfidence90(miu, std_dev_miu);
		System.out.println();
		System.out.print("MIU 95%: ");
		printConfidence95(miu, std_dev_miu);
		System.out.println();
		System.out.println();
		
		printConfidenceOne("s[i]", s, ISI, std_dev_S);
		printConfidenceOne("m[j]", m, IMI, std_dev_M);
		printConfidenceOne("f[k]", f, IFI, std_dev_F);

		printConfidenceTwo("niuSM[i][j]", "S\\M", niuSM, ISI, IMI, std_dev_SM);
		printConfidenceTwo("niuSF[i][k]", "S\\F", niuSF, ISI, IFI, std_dev_SF);
		printConfidenceTwo("niuMF[j][k]", "M\\F", niuMF, IMI, IFI, std_dev_MF);
		
		printConfidenceTwo("niuSMF[j][k]", "SMF::S=0,M\\F", niuSMF[0], IMI, IFI, std_dev_MF);
		printConfidenceTwo("niuSMF[j][k]", "SMF::S=1,M\\F", niuSMF[1], IMI, IFI, std_dev_MF);
		
		
		
		
		
		System.out.println("std_dev_error: " + std_dev_error);
		System.out.println("std_dev_miu: " + std_dev_miu);
		System.out.println("std_dev_S: " + std_dev_S);
		System.out.println("std_dev_M: " + std_dev_M);
		System.out.println("std_dev_F: " + std_dev_F);
		System.out.println("std_dev_SM: " + std_dev_SM);
		System.out.println("std_dev_SF: " + std_dev_SF);
		System.out.println("std_dev_MF: " + std_dev_MF);
		System.out.println("std_dev_SMF: " + std_dev_SMF);
		
	}
	
	private void printConfidence90(double value, double std_dev) {
		printConfidence(value, 1.645*std_dev);
	}

	private void printConfidence95(double value, double std_dev) {
		printConfidence(value, 1.960*std_dev);
	}

	private void printConfidence(double value, double delta) {
		System.out.print("[");
		System.out.format("%.3f", value-delta);
		System.out.print(";");
		System.out.format("%.3f", value+delta);
		System.out.print("]");
	}
	
	private void printConfidenceOne(String label, double []array, int size, double std_dev) {
		System.out.println(label);
		System.out.println("90% : 95%");
		for(int i=0; i<size; i++) {
			printConfidence90(array[i], std_dev);
			System.out.print(":");
			printConfidence95(array[i], std_dev);
			System.out.println();
		}
		System.out.println();
	}
	
	private void printConfidenceTwo(String label1, String label2, double [][]array, int size1, int size2, double std_dev) {
		System.out.println(label1);
		System.out.print(label2 + ":");
		for(int j=0; j<size2; j++) {
			System.out.print( j+1 );
			System.out.print( "::" );
		}
		System.out.println();
		System.out.print(":");
		for(int j=0; j<size2; j++) {
			System.out.print("90% : 95% : ");
		}
		System.out.println();
		for(int i=0; i<size1; i++) {
			System.out.print(i+1);
			System.out.print(":");
			for(int j=0; j<size2; j++) {
				printConfidence90(array[i][j], std_dev);
				System.out.print(":");
				printConfidence95(array[i][j], std_dev);
				System.out.print(":");
			}
			System.out.println();
		}
		System.out.println();
	}
	
	private double computeMean(int i, int j, int k, int ISI, int IMI, int IFI, int R) {
		double mean = 0;
		int numbers = 0;
		for(int ii=0; ii<ISI; ii++) {
			for(int jj=0; jj<IMI; jj++) {
				for(int kk=0; kk<IFI; kk++) {
					for(int ll=0; ll<R; ll++) {
						if(
							(i==ISI || i==ii) &&
							(j==IMI || j==jj) &&
							(k==IFI || k==kk) )
						{
							mean += y[ii][jj][kk][ll];
							numbers ++;
						}
					}
				}
			}
		}
		return mean / (double) numbers;
	}
	
	
}
